// MongoStatement.java

/**
 *      Copyright (C) 2008 10gen Inc.
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */

package com.mongodb.jdbc;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.SQLWarning;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;
import com.mongodb.jdbc.Executor.DBObjAndCollection;

public class MongoStatement implements Statement {
	
	
	Map<DBCollection,List<DBObject>> _dbToDBObject;

    MongoStatement( MongoConnection conn , int type, int concurrency, int holdability){
        _conn = conn;
        _type = type;
        _concurrency = concurrency;
        _holdability = holdability;
        _dbToDBObject = new HashMap<DBCollection,List<DBObject>>();
        
        if ( _type != 0 )
            throw new UnsupportedOperationException( "type not supported yet" );
        if ( _concurrency != 0 )
            throw new UnsupportedOperationException( "concurrency not supported yet" );
        if ( _holdability != 0 )
            throw new UnsupportedOperationException( "holdability not supported yet" );
        
    }

    // --- batch ---
    
    public void addBatch(String sql) throws SQLException {
    	try {
    		boolean flag = true;
    		
    		DBObjAndCollection DAC = new Executor( _conn, sql ).writeopAddBat();
    		
    		Set<DBCollection>  DBC =_dbToDBObject.keySet();
    		
    		for (DBCollection dbCollection : DBC) {
//    			System.out.println(dbCollection.getName()+":"+DAC.getColl().getName());
				if(dbCollection.getName().equals(DAC.getColl().getName())){
					_dbToDBObject.get(dbCollection).add(DAC.getDbObj());
					flag = false;
					break;
				}
			}
    		
    		if(flag){
    			List<DBObject> DBObjects = new ArrayList<DBObject>();
    			DBObjects.add(DAC.getDbObj());
    			_dbToDBObject.put(DAC.getColl(), DBObjects);
    		}
		} catch (MongoSQLException e) {
			e.printStackTrace();
		}
    }
    
    public void clearBatch(){
    	_dbToDBObject.clear();
    }
    
    public int[] executeBatch() throws SQLException{
    	for (DBCollection dbc : _dbToDBObject.keySet()) {
    		dbc.insert(_dbToDBObject.get(dbc));
		}
    	
    	clearBatch();
    	
		return null;
    }
    
    // --- random
    
    public void cancel(){
        throw new RuntimeException( "not supported yet - can be" );
    }
    
    public void close(){
    	if (_last != null) {
    		_last.close();
		}
//        _conn = null;
    }

    public Connection getConnection(){
        return _conn;
    }

    public boolean isClosed(){
        return _conn == null;
    }

    public boolean isPoolable(){
        return true;
    }

    public void setPoolable(boolean poolable){
        if ( ! poolable )
            throw new RuntimeException( "why don't you want me to be poolable?" );
    }
    
    public void clearWarnings(){
        throw new RuntimeException( "not supported yet - can be" );        
    }

    // --- writes ----
    
    public boolean execute(String sql){
        throw new RuntimeException( "execute not done" );
    }
    public boolean execute(String sql, int autoGeneratedKeys){
        throw new RuntimeException( "execute not done" );
    }
    public boolean execute(String sql, int[] columnIndexes){
        throw new RuntimeException( "execute not done" );
    }
    public boolean execute(String sql, String[] columnNames){
        throw new RuntimeException( "execute not done" );
    }

    public int executeUpdate(String sql)
        throws SQLException {
        return new Executor( _conn, sql ).writeop();
    }
    public int executeUpdate(String sql, int autoGeneratedKeys){
        throw new RuntimeException( "executeUpdate not done" );
    }
    public int executeUpdate(String sql, int[] columnIndexes){
        throw new RuntimeException( "executeUpdate not done" );
    }
    public int executeUpdate(String sql, String[] columnNames){
        throw new RuntimeException( "executeUpdate not done" );
    }

    public int getUpdateCount(){
        throw new RuntimeException( "getUpdateCount not done" );
    }

    public ResultSet getGeneratedKeys(){
        throw new RuntimeException( "getGeneratedKeys notn done" );
    }

    // ---- reads -----
    
    public ResultSet executeQuery(String sql)
        throws SQLException {
        // TODO
        // handle max rows
    	Executor executor = new Executor( _conn, sql );
        DBCursor cursor = executor.query();
        if ( _fetchSize > 0 )
            cursor.batchSize( _fetchSize );
        if ( _maxRows > 0 )
            cursor.limit( _maxRows );
        
        _last = new MongoResultSet( executor.lastFieldMapping, cursor );
        return _last;
    }

    public int getQueryTimeout(){
        throw new RuntimeException( "query timeout not done" );
    }
    public void setQueryTimeout(int seconds){
        throw new RuntimeException( "query timeout not done" );
    }
    
    // ---- fetch modifiers ----


    public int getFetchSize(){
        return _fetchSize;
    }
    public void setFetchSize(int rows){
        _fetchSize = rows;
    }

    public int getMaxRows(){
        return _maxRows;
    }
    public void setMaxRows(int max){
        _maxRows = max;
    }
    
    public int getFetchDirection(){
        throw new RuntimeException( "fetch direction not done yet" );
    }
    public void setFetchDirection(int direction){
        throw new RuntimeException( "fetch direction not done yet" );
    }
        
    public int getMaxFieldSize(){
        throw new RuntimeException( "max field size not supported" );
    }
    public void setMaxFieldSize(int max){
        throw new RuntimeException( "max field size not supported" );
    }
    
    
    public boolean getMoreResults(){
        throw new RuntimeException( "getMoreResults not supported" );
    }
    public boolean getMoreResults(int current){
        throw new RuntimeException( "getMoreResults not supported" );
    }

    public ResultSet getResultSet(){
        return _last;
    }

    // ---- more random -----


    public SQLWarning getWarnings(){
        throw new UnsupportedOperationException( "warning not supported yet" );
    }

    public void setCursorName(String name){
        throw new UnsupportedOperationException( "can't set cursor name" );
    }
    
    public void setEscapeProcessing(boolean enable){
        if ( ! enable )
            throw new RuntimeException( "why do you want to turn escape processing off?" );
    }

    public int getResultSetConcurrency(){
        return _concurrency;
    }
    public int getResultSetHoldability(){
        return _holdability;
    }
    public int getResultSetType(){
        return _type;
    }

    public <T> T unwrap(Class<T> iface)
        throws SQLException {
        throw new UnsupportedOperationException();
    }

    public boolean isWrapperFor(Class<?> iface)
        throws SQLException {
        throw new UnsupportedOperationException();
    }

    MongoConnection _conn;

    final int _type;
    final int _concurrency;
    final int _holdability;

    int _fetchSize = 0;
    int _maxRows = 0;

    MongoResultSet _last;

	@Override
	public void closeOnCompletion() throws SQLException {
		// TODO Auto-generated method stub
		
	}

	@Override
	public boolean isCloseOnCompletion() throws SQLException {
		// TODO Auto-generated method stub
		return false;
	}
}
